package com.kmxd.ams.app.system;

import static com.kmxd.ams.core.common.constant.ConfigConst.FILE_CATEGORY;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kmxd.ams.client.system.ISysConfigSvc;
import com.kmxd.ams.client.system.dto.SysConfigAddDTO;
import com.kmxd.ams.client.system.dto.SysConfigEditDTO;
import com.kmxd.ams.client.system.dto.SysConfigQueryDTO;
import com.kmxd.ams.client.system.vo.*;
import com.kmxd.ams.core.common.constant.CacheConst;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.StatusEnum;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.JSONUtils;
import com.kmxd.ams.infra.system.entity.SysConfig;
import com.kmxd.ams.infra.system.mapper.SysConfigMapper;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 系统配置 服务实现类
 *
 * @author admin
 * @since 2021-06-23
 */
@Service
@AllArgsConstructor
@Slf4j
@CacheConfig(cacheNames = CacheConst.CACHE_PREFIX_SYS_CONFIG)
public class SysConfigSvcImpl extends ServiceImpl<SysConfigMapper, SysConfig>
    implements ISysConfigSvc {

  private SysConfigMapper sysConfigMapper;
  private RedisTemplate redisTemplate;

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public Page<SysConfigListVO> selectPage(Page reqPage, SysConfigQueryDTO req) {
    LambdaQueryWrapper<SysConfig> queryWrapper =
        QueryGen.init(new QueryWrapper<SysConfig>(), req).lambda();
    queryWrapper.orderByDesc(SysConfig::getCreateTime);
    Page<SysConfig> page = sysConfigMapper.selectPage(reqPage, queryWrapper);
    Page<SysConfigListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), SysConfigListVO.class));
    return voPage;
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public List<SysConfigListVO> selectList(SysConfigQueryDTO req) {
    LambdaQueryWrapper<SysConfig> queryWrapper =
        QueryGen.init(new QueryWrapper<SysConfig>(), req).lambda();
    queryWrapper.orderByDesc(SysConfig::getCreateTime);
    List<SysConfig> list = sysConfigMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, SysConfigListVO.class);
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public List<SysConfig> selectAll() {
    LambdaQueryWrapper<SysConfig> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.orderByDesc(SysConfig::getSort);
    return sysConfigMapper.selectList(queryWrapper);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(SysConfigAddDTO req) {
    if (!this.checkUniqueConfigKey(req.getCode().trim(), null)) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "参数键名已存在");
    }
    SysConfig entity = BeanUtil.copyProperties(req, SysConfig.class);
    entity.setCode(entity.getCode().trim());
    sysConfigMapper.insert(entity);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(SysConfigEditDTO req) {
    if (!this.checkUniqueConfigKey(req.getCode(), req.getId())) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "参数键名已存在");
    }
    SysConfig entity = BeanUtil.copyProperties(req, SysConfig.class);
    entity.setCode(entity.getCode().trim());
    sysConfigMapper.updateById(entity);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    sysConfigMapper.deleteBatchIds(idList);
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public SysConfigVO view(Long id) {
    SysConfig entity = sysConfigMapper.selectById(id);
    return BeanUtil.copyProperties(entity, SysConfigVO.class);
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public FlowConfigVO getFlowConfig() {
    String configStr = getConfigContentByKey(ConfigConst.FLOW_CONFIG);
    FlowConfigVO config = new FlowConfigVO();
    JSONObject json =
        JSONUtil.isTypeJSON(configStr) ? JSONUtils.parseObj(configStr) : JSONUtil.createObj();
    config.setFlowTransferInner(json.getBool("flow_transfer_inner", Boolean.FALSE));
    config.setFlowTransferFonds(json.getBool("flow_transfer_fonds", Boolean.FALSE));
    config.setFlowLongStorage(json.getBool("flow_long_storage", Boolean.FALSE));
    config.setFlowSharePublish(json.getBool("flow_share_publish", Boolean.FALSE));
    config.setFlowInOutArch(json.getBool("flow_in_out_arch", Boolean.FALSE));
    config.setFlowArchPublish(json.getBool("flow_arch_publish", Boolean.FALSE));
    config.setFlowArchIdentify(json.getBool("flow_arch_identify", Boolean.FALSE));
    config.setFlowHallPublish(json.getBool("flow_hall_publish", Boolean.FALSE));
    config.setFlowUtilize(json.getBool("flow_utilize", Boolean.FALSE));
    config.setFlowFondsUtilize(json.getBool("flow_fonds_utilize", Boolean.FALSE));
    config.setFlowAssist(json.getBool("flow_assist", Boolean.FALSE));
    return config;
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public SxConfigVO getSxConfig() {
    String configStr = getConfigContentByKey(ConfigConst.SX_CONFIG);
    SxConfigVO config = new SxConfigVO();
    JSONObject json = JSONUtil.createObj();
    try {
      json = JSONUtil.isTypeJSON(configStr) ? JSONUtils.parseObj(configStr) : JSONUtil.createObj();
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      log.error("获取四性检测配置项错误！");
    }
    config.setSxInterface(json.getBool("sx_interface", Boolean.FALSE));
    config.setSxTransferInner(json.getBool("sx_transfer_inner", Boolean.FALSE));
    config.setSxTransferFonds(json.getBool("sx_transfer_fonds", Boolean.FALSE));
    config.setSxLongStorage(json.getBool("sx_long_storage", Boolean.FALSE));
    config.setSxSharePublish(json.getBool("sx_share_publish", Boolean.FALSE));
    return config;
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public SxCheckVO getSxCheck() {
    String configStr = getConfigContentByKey(ConfigConst.SX_CHECK);
    SxCheckVO config = new SxCheckVO();
    JSONObject json = JSONUtil.createObj();
    try {
      json = JSONUtil.isTypeJSON(configStr) ? JSONUtils.parseObj(configStr) : JSONUtil.createObj();
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      log.error("获取四性检测配置项错误！");
    }
    config.setDocCode(json.getStr("docCode", "docCode"));
    config.setVolSequence(json.getStr("volSequence", "volSequence"));
    config.setArchCode(json.getStr("archCode", "archCode"));
    config.setPageNum(json.getStr("pageNum", "pageNum"));
    config.setFilesNum(json.getStr("filesNum", "filesNum"));
    config.setSecurity(json.getStr("security", "security"));
    config.setSm3Field(json.getStr("sm3", "sm3"));
    config.setSecurityName(json.getStr("securityName", "秘密,机密,绝密"));
    return config;
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public List<FileCategoryVO> getFileCategory() {
    SysConfig config =
        getOne(
            Wrappers.<SysConfig>lambdaQuery()
                .eq(SysConfig::getCode, FILE_CATEGORY)
                .last(" limit 1"));
    if (ObjectUtil.isNull(config)) {
      return Lists.newArrayList();
    }
    return JSONUtil.toList(config.getContent(), FileCategoryVO.class);
  }

  @Override
  public SysConfig getConfigValueByKey(String key) {
    ISysConfigSvc sysConfigSvc = SpringUtil.getBean(ISysConfigSvc.class);
    List<SysConfig> lists = sysConfigSvc.selectAll();
    if (ObjectUtil.isEmpty(lists)) {
      lists = this.selectAll();
    }
    return lists.stream()
        .filter(
            x ->
                ObjectUtil.equal(x.getCode(), key.trim())
                    && ObjectUtil.equal(x.getStatus(), StatusEnum.YES.getCode()))
        .findFirst()
        .orElse(null);
  }

  @Override
  public String getConfigContentByKey(String key) {
    SysConfig sysConfig = getConfigValueByKey(key.trim());
    return ObjectUtil.isNotEmpty(sysConfig) ? sysConfig.getContent() : null;
  }

  @CacheEvict(allEntries = true)
  @Override
  public void clearAllCache() {
    Set<String> keys = redisTemplate.keys("*");
    for (String key : keys) {
      redisTemplate.delete(key);
    }
    log.info("清除系统参数缓存");
  }

  private Boolean checkUniqueConfigKey(String value, Long id) {
    if (StrUtil.isBlank(value)) {
      return true;
    }
    id = Objects.isNull(id) ? -1L : id;
    SysConfig entity =
        sysConfigMapper.selectOne(
            Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getCode, value));
    return Objects.isNull(entity) || NumberUtil.equals(entity.getId(), id);
  }
}
